home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / regsub.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  8KB  |  339 lines

  1. /* vi:ts=4:sw=4
  2.  * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  3.  *
  4.  * This is NOT the original regular expression code as written by
  5.  * Henry Spencer. This code has been modified specifically for use
  6.  * with the VIM editor, and should not be used apart from compiling
  7.  * VIM. If you want a good regular expression library, get the
  8.  * original code. The copyright notice that follows is from the
  9.  * original.
  10.  *
  11.  * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  12.  *
  13.  * regsub
  14.  *
  15.  *        Copyright (c) 1986 by University of Toronto.
  16.  *        Written by Henry Spencer.  Not derived from licensed software.
  17.  *
  18.  *        Permission is granted to anyone to use this software for any
  19.  *        purpose on any computer system, and to redistribute it freely,
  20.  *        subject to the following restrictions:
  21.  *
  22.  *        1. The author is not responsible for the consequences of use of
  23.  *                this software, no matter how awful, even if they arise
  24.  *                from defects in it.
  25.  *
  26.  *        2. The origin of this software must not be misrepresented, either
  27.  *                by explicit claim or by omission.
  28.  *
  29.  *        3. Altered versions must be plainly marked as such, and must not
  30.  *                be misrepresented as being the original software.
  31.  *
  32.  * $Log:        regsub.c,v $
  33.  * Revision 1.2  88/04/28  08:11:25  tony
  34.  * First modification of the regexp library. Added an external variable
  35.  * 'reg_ic' which can be set to indicate that case should be ignored.
  36.  * Added a new parameter to regexec() to indicate that the given string
  37.  * comes from the beginning of a line and is thus eligible to match
  38.  * 'beginning-of-line'.
  39.  *
  40.  * Revisions by Olaf 'Rhialto' Seibert, rhialto@cs.kun.nl:
  41.  * Changes for vi: (the semantics of several things were rather different)
  42.  * - Added lexical analyzer, because in vi magicness of characters
  43.  *   is rather difficult, and may change over time.
  44.  * - Added support for \< \> \1-\9 and ~
  45.  * - Left some magic stuff in, but only backslashed: \| \+
  46.  * - * and \+ still work after \) even though they shouldn't.
  47.  */
  48.  
  49. #include "vim.h"
  50. #include "globals.h"
  51. #include "proto.h"
  52.  
  53. #ifdef MSDOS
  54. # define __ARGS(a)    a
  55. #endif
  56.  
  57. #define CASECONVERT
  58.  
  59. #include <stdio.h>
  60. #include "regexp.h"
  61. #include "regmagic.h"
  62.  
  63. #ifdef LATTICE
  64. # include <sys/types.h>        /* for size_t */
  65. #endif
  66.  
  67. #ifndef CHARBITS
  68. #define UCHARAT(p)      ((int)*(char_u *)(p))
  69. #else
  70. #define UCHARAT(p)      ((int)*(p)&CHARBITS)
  71. #endif
  72.  
  73. extern char_u        *reg_prev_sub;
  74.  
  75. #ifdef CASECONVERT
  76.     /*
  77.      * We should define ftpr as a pointer to a function returning a pointer to
  78.      * a function returning a pointer to a function ...
  79.      * This is impossible, so we declare a pointer to a function returning a
  80.      * pointer to a function returning void. This should work for all compilers.
  81.      */
  82. typedef void (*(*fptr) __ARGS((char_u *, int)))();
  83. static fptr strnfcpy __ARGS((fptr, char_u *, char_u *, int));
  84.  
  85. static fptr do_Copy __ARGS((char_u *, int));
  86. static fptr do_upper __ARGS((char_u *, int));
  87. static fptr do_Upper __ARGS((char_u *, int));
  88. static fptr do_lower __ARGS((char_u *, int));
  89. static fptr do_Lower __ARGS((char_u *, int));
  90.  
  91.     static fptr
  92. do_Copy(d, c)
  93.     char_u *d;
  94.     int c;
  95. {
  96.     *d = c;
  97.  
  98.     return (fptr)do_Copy;
  99. }
  100.  
  101.     static fptr
  102. do_upper(d, c)
  103.     char_u *d;
  104.     int c;
  105. {
  106.     *d = TO_UPPER(c);
  107.  
  108.     return (fptr)do_Copy;
  109. }
  110.  
  111.     static fptr
  112. do_Upper(d, c)
  113.     char_u *d;
  114.     int c;
  115. {
  116.     *d = TO_UPPER(c);
  117.  
  118.     return (fptr)do_Upper;
  119. }
  120.  
  121.     static fptr
  122. do_lower(d, c)
  123.     char_u *d;
  124.     int c;
  125. {
  126.     *d = TO_LOWER(c);
  127.  
  128.     return (fptr)do_Copy;
  129. }
  130.  
  131.     static fptr
  132. do_Lower(d, c)
  133.     char_u *d;
  134.     int c;
  135. {
  136.     *d = TO_LOWER(c);
  137.  
  138.     return (fptr)do_Lower;
  139. }
  140.  
  141.     static fptr
  142. strnfcpy(f, d, s, n)
  143.     fptr f;
  144.     char_u *d;
  145.     char_u *s;
  146.     int n;
  147. {
  148.     while (n-- > 0) {
  149.         f = (fptr)(f(d, *s));        /* Turbo C complains without the typecast */
  150.         if (!*s++)
  151.             break;
  152.         d++;
  153.     }
  154.  
  155.     return f;
  156. }
  157. #endif
  158.  
  159. /*
  160.  * regtilde: replace tildes in the pattern by the old pattern
  161.  *
  162.  * Short explanation of the tilde: it stands for the previous replacement
  163.  * pattern. If that previous pattern also contains a ~ we should go back
  164.  * a step further... but we insert the previous pattern into the current one
  165.  * and remember that.
  166.  * This still does not handle the case where "magic" changes. TODO?
  167.  *
  168.  * New solution: The tilde's are parsed once before the first call to regsub().
  169.  * In the old solution (tilde handled in regsub()) is was possible to get an
  170.  * endless loop.
  171.  */
  172.     char_u *
  173. regtilde(source, magic)
  174.     char_u    *source;
  175.     int        magic;
  176. {
  177.     char_u    *newsub = NULL;
  178.     char_u    *tmpsub;
  179.     char_u    *p;
  180.     int        len;
  181.     int        prevlen;
  182.  
  183.     for (p = source; *p; ++p)
  184.     {
  185.         if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic))
  186.         {
  187.             if (reg_prev_sub)
  188.             {
  189.                     /* length = len(current) - 1 + len(previous) + 1 */
  190.                 prevlen = STRLEN(reg_prev_sub);
  191.                 tmpsub = alloc((unsigned)(STRLEN(source) + prevlen));
  192.                 if (tmpsub)
  193.                 {
  194.                         /* copy prefix */
  195.                     len = (int)(p - source);    /* not including ~ */
  196.                     STRNCPY(tmpsub, source, (size_t)len);
  197.                         /* interpretate tilde */
  198.                     STRCPY(tmpsub + len, reg_prev_sub);
  199.                         /* copy postfix */
  200.                     if (!magic)
  201.                         ++p;                    /* back off \ */
  202.                     STRCAT(tmpsub + len, p + 1);
  203.  
  204.                     free(newsub);
  205.                     newsub = tmpsub;
  206.                     p = newsub + len + prevlen;
  207.                 }
  208.             }
  209.             else if (magic)
  210.                 STRCPY(p, p + 1);                /* remove '~' */
  211.             else
  212.                 STRCPY(p, p + 2);                /* remove '\~' */
  213.         }
  214.         else if (*p == '\\' && p[1])            /* skip escaped characters */
  215.             ++p;
  216.     }
  217.  
  218.     free(reg_prev_sub);
  219.     if (newsub)
  220.     {
  221.         source = newsub;
  222.         reg_prev_sub = newsub;
  223.     }
  224.     else
  225.         reg_prev_sub = strsave(source);
  226.     return source;
  227. }
  228.  
  229. /*
  230.  - regsub - perform substitutions after a regexp match
  231.  *
  232.  * Returns the size of the replacement, including terminating \0.
  233.  */
  234.     int
  235. regsub(prog, source, dest, copy, magic)
  236.     regexp           *prog;
  237.     char_u           *source;
  238.     char_u           *dest;
  239.     int             copy;
  240.     int             magic;
  241. {
  242.     register char_u  *src;
  243.     register char_u  *dst;
  244.     register int    c;
  245.     register int    no;
  246.     register int    len;
  247. #ifdef CASECONVERT
  248.     fptr            func = (fptr)do_Copy;
  249. #endif
  250.  
  251.     if (prog == NULL || source == NULL || dest == NULL)
  252.     {
  253.         emsg(e_null);
  254.         return 0;
  255.     }
  256.     if (UCHARAT(prog->program) != MAGIC)
  257.     {
  258.         emsg(e_re_corr);
  259.         return 0;
  260.     }
  261.     src = source;
  262.     dst = dest;
  263.  
  264.     while ((c = *src++) != '\0')
  265.     {
  266.         no = -1;
  267.         if (c == '&' && magic)
  268.             no = 0;
  269.         else if (c == '\\' && *src != NUL)
  270.         {
  271.             if (*src == '&' && !magic)
  272.             {
  273.                 ++src;
  274.                 no = 0;
  275.             }
  276.             else if ('0' <= *src && *src <= '9')
  277.             {
  278.                 no = *src++ - '0';
  279.             }
  280. #ifdef CASECONVERT
  281.             else if (strchr("uUlLeE", *src))
  282.             {
  283.                 switch (*src++)
  284.                 {
  285.                 case 'u':    func = (fptr)do_upper;
  286.                             continue;
  287.                 case 'U':    func = (fptr)do_Upper;
  288.                             continue;
  289.                 case 'l':    func = (fptr)do_lower;
  290.                             continue;
  291.                 case 'L':    func = (fptr)do_Lower;
  292.                             continue;
  293.                 case 'e':
  294.                 case 'E':    func = (fptr)do_Copy;
  295.                             continue;
  296.                 }
  297.             }
  298. #endif
  299.         }
  300.         if (no < 0)           /* Ordinary character. */
  301.         {
  302.             if (c == '\\' && *src != NUL)
  303.                 c = *src++;
  304.             if (copy)
  305.             {
  306. #ifdef CASECONVERT
  307.                 func = (fptr)(func(dst, c));
  308.                             /* Turbo C complains without the typecast */
  309. #else
  310.                 *dst = c;
  311. #endif
  312.             }
  313.             dst++;
  314.         }
  315.         else if (prog->startp[no] != NULL && prog->endp[no] != NULL)
  316.         {
  317.             len = (int)(prog->endp[no] - prog->startp[no]);
  318.             if (copy)
  319.             {
  320. #ifdef CASECONVERT
  321.                 func = strnfcpy(func, dst, prog->startp[no], len);
  322. #else
  323.                 (void) STRNCPY(dst, prog->startp[no], len);
  324. #endif
  325.             }
  326.             dst += len;
  327.             if (copy && len != 0 && *(dst - 1) == '\0') { /* strncpy hit NUL. */
  328.                 emsg(e_re_damg);
  329.                 goto exit;
  330.             }
  331.         }
  332.     }
  333.     if (copy)
  334.         *dst = '\0';
  335.  
  336. exit:
  337.     return (int)((dst - dest) + 1);
  338. }
  339.